#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <boost/algorithm/string.hpp>

#include <getopt.h>

class RSTTable
{
public:
	RSTTable(const std::string &sep = std::string("\t"))
		: sep_( "\t" ), new_row_flag( true )
	{
	}

	void SetSeperator( const std::string &sep ) { sep_ = sep; }
	void SetLineSeperator( const std::string &line_sep ) { line_sep_ = line_sep; }

	void AddLine(const std::string &line)
	{
		if( line_sep_.empty() || line == line_sep_ ) {
			new_row_flag = true;
			return;
		}

		// split
		std::vector< std::string > fields;
		boost::split( fields, line, boost::is_any_of(sep_) );

		// get max field and field's max length
		for( size_t i = 0; i < fields.size(); i++ ) {
			size_t len = get_display_len( fields.at(i) );
			if( field_len_.size() < i+1 )
				field_len_.push_back( len );
			if( len > field_len_.at(i) )
				field_len_.at(i) = len;
		}

		// add to table
		if( new_row_flag ) {
			table_.push_back( std::list< std::vector< std::string > >() );
			if( !line_sep_.empty() )
				new_row_flag = false;
		}

		table_.rbegin()->push_back( fields );
	}

	void PrintTable()
	{
		print_table_line();
		for( auto it = table_.begin(); it != table_.end(); ++it ) {
			// print table row
			for( const auto &vec : *it ) {
				print_char( '|' );
				for( size_t i = 0; i < field_len_.size(); i++ ) {
					if( i < vec.size() ) {
						print_char( ' ' );
						std::cout << vec.at(i);
						print_char( ' ', field_len_.at(i) - get_display_len( vec.at(i) ) );
						print_char( ' ' );
					}
					else {
						print_char( ' ', field_len_.at(i) + 2);
					}
					print_char( '|' );
				}
				std::cout << std::endl;
			}

			// print table line
			if( it == table_.begin() )
				print_table_line( '=' );
			else 
				print_table_line();
		}
	}


private:
	void print_table_line( const char c = '-' )
	{
		std::cout << '+';
		for( auto len : field_len_ ) {
			print_char( c, len + 2);
			std::cout << '+';
		}
		std::cout << std::endl;
	}

	void print_char( const char c, size_t len = 1 )
	{
		for( size_t i = 0; i < len; i++ )
			std::cout << c;
	}

	/*
	 * only detect utf8 string
	 * ascii character display length is 1, others is 2
	 */
	const size_t get_display_len(const std::string &str)
	{
		size_t len = 0;
		size_t pos = 0;

		const size_t str_len = str.size();
		const unsigned char *data = (const unsigned char *)str.data();

		while( pos < str_len ) {
			if( !(data[pos] & 0x80) ) { // ascii
				len++;
				pos++;
			}
			else { 
				len += 2;
				pos += utf8_world_len( data[pos] );
			}
		}

		return len;
	}

	// utf8 world storage length
	int static utf8_world_len( unsigned char c )
	{
		int len = 0;
		for( int mark = 0x80; mark & c ; mark = (mark >> 1) )
			len++;
		return len;
	}

private:
	std::string sep_; // field seperator
	std::string line_sep_; // line sepperator

	std::vector< size_t > field_len_;
	bool new_row_flag;
	std::list< std::list< std::vector< std::string > > > table_;
};

int main( int argc, char *argv[] )
{
	RSTTable table;

	const char *short_opt = "f:l:h";
	int opt;
	while( (opt = getopt( argc, argv, short_opt ) ) != -1 ) {
		switch(opt) {
		case 'f':
			table.SetSeperator( optarg );
			break;
		case 'l':
			table.SetLineSeperator( optarg );
			break;
		case 'h':
		default:
			std::cerr << argv[0] << " [-f field_seperator] [-l line_seperator] [-h]" << std::endl;
			return 1;
		}
	}

	std::string line;
	while( !std::cin.eof() ) {
		getline(std::cin, line);
		boost::trim( line );
		// std::cout << line << std::endl;
		table.AddLine( line );
	}

	table.PrintTable();
	return 0;
}

